<!doctype html>
<meta encoding="utf-8">
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
<style>
  #warning {
    color: red;
    background-color: rgba(255,0,0,0.1);
  }
  h4 {
    margin: 0;
    font-size: 1.1em;
    font-variant: small-caps;
  }
  h5 {
    font-size: 1em;
  }
  p {
    margin: 0.6em 0 1.2em 0;
  }
  .hide {
    display:none;
  }
  #demos {
    display: flex;
    border-top: 1px solid gray;
    border-bottom: 1px solid gray;
  }
  #demos > div {
    display: inline-block;
    flex-grow: 1;
    border-right: 1px solid gray;
  }
  iframe {
    border: 0;
    margin: 16px;
    width: 100px;
    height: 100px;
    box-shadow: 0px 0px 5px 5px rgba(0,0,0,0.75);
  }
</style>
<script src="iframeResize.js"></script>
<script>
iframeResize.setupWindow();
</script>
<body>
<h1 id="warning" class="hide">ResizeObserver not detected. Demo will not work.</h1>
<h3>ResizeObserver iframe sizing example</h3>
<div id="demos" style="display:flex">
  <div>
    <p>Example 1: text inside a 50px wide iframe</p>
    <iframe src="iframe_embed_text.html" style="width:50px"></iframe>
  </div>
  <div>
    <p>Example 2: text inside a 200px wide iframe</p>
    <iframe src="iframe_embed_text.html" style="width:200px"></iframe>
  </div>
  <div>
    <p>Example 3: image inside a 50px wide iframe</p>
    <iframe src="iframe_embed_image.html" style="width:50px"></iframe>
  </div>
  <div>
    <p>Example 4: text inside a 400px wide iframe</p>
    <iframe src="iframe_embed_image.html" style="width:400px;height: 400px;"></iframe>
  </div>
</div>

<main>
<p>Sizing of embedded iframes to their content box size is a common webdev problem. ResizeObserver can help with a solution.</p>
<p>Full solution needs to solve several distinct problems:</p>

<h5>1) iframe needs to know when its size has changed.</h5>
<p>ResizeObserver solves this by observing <code>&ltbody></code>'s size changes.
Note: this only works in standards mode, because body height is 100% in quirks.
</p>
<pre>
  // This code is executed inside iframe
  let ro = new ResizeObserver(entries => {
    let idealSize = computeIdealSize(isImage);
    window.parent.postMessage({
      name: "iframeResize",
      width: idealSize.width,
      height: idealSize.height
    }, '*');
  });
  ro.observe(document.body);
</pre>
<h5>2) iframe must decide what its size should be.</h5>
<p>When document is text, the width of text will always be at least
initial width of iframe. Height will be determined by text length.
</p>
<p>When document is image, width and height are determined by image size.</p>

<h5>3) iframe needs to communicate its size to containing window.</h5>
<p>This can be done with <code>postMessage</code> API.</p>
<pre>
  // This code goes into containing window
  window.addEventListener("message", ev => {
    if (ev.data && ev.data.name == "iframeResize") {
      let iframe = findEventSourceIframe(ev.source);
      if (iframe) {
        iframe.style.width = ev.data.width + "px";
        iframe.style.height = ev.data.height + "px";
      }
    }
  }, false);
</pre>

<p><a href="iframeResize.js">iframeResize.js</a> is a library implementation.
</body>
